// Copyright (c) 2009-2010, Jeremy Brewer
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.

package galaxie500.collections;

import java.util.Arrays;

/**
 * Class which makes appending doubles efficient
 * 
 * Faster than an ArrayList<Double> because it uses an array internally. This
 * also makes converting to a double[] easy because no Double -> double
 * conversion is required.
 * 
 * TODO: more documentation
 * 
 * @author Jeremy Brewer
 */
public class DoubleList {
  private int size = 0;
  private double[] list;
  private static int GROWTH_FACTOR = 2;

  public DoubleList() {
    this(10);
  }

  public DoubleList(int initialCapacity) {
    list = new double[initialCapacity];
    size = 0;
  }

  public DoubleList(double[] list) {
    this.list = list;
    size = list.length;
  }

  public double get(int i) {
    return list[i];
  }

  public void set(int i, double value) {
    list[i] = value;
  }

  public int size() {
    return size;
  }

  public int capacity() {
    return list.length;
  }
  
  public boolean isEmpty() {
    return size == 0;
  }

  public void add(double value) {
    if (size >= list.length) {
      resize(size * GROWTH_FACTOR);
    }
    list[size] = value;
    size++;
  }

  /**
   * Resizes the internal array to be large enough to hold newSize elements.
   * 
   * @param newSize The number of elements to hold in the array
   */
  public void resize(int newSize) {
    if (newSize < size) {
      size = newSize;
      if ((list.length / newSize) < GROWTH_FACTOR) {
        // Don't do an array resize and copy for small reduction in size.
        return;
      }
    }
    list = Arrays.copyOf(list, newSize);
  }

  /**
   * @return A reference to the internal array, which in general will not be the
   *         same length as size() returns.
   */
  public double[] list() {
    return list;
  }

  /**
   * @return A copy of the internal array.
   */
  public double[] toArray() {
    if (size == 0) return null;
    return Arrays.copyOf(list, size);
  }
}
